using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

using TowerDef_s_enseLibrary.map;
using TowerDef_s_enseLibrary.gui;
using TowerDef_s_enseLibrary.game;
using TowerDef_s_enseLibrary.player;
using TowerDef_s_enseLibrary.core;

namespace TowerDef_s_ense
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game : Microsoft.Xna.Framework.Game
    {
        #region variables

        const float STARTPOINTX = 16;
        const float STARTPOINTY = 48;

        readonly GraphicsDeviceManager _graphics;
        SpriteBatch _spriteBatch;

        readonly Map _map = new Map();
        readonly Background _background = new Background();
        readonly MouseInfos _mouseInfos = new MouseInfos();

        Player _player;
        WaveManager _waveManager;
        TowerMenu _towermenu;
        Button _arrowButton;
        Button _slowButton;
        Button _spikeButton;

        #endregion variables

        #region functions

        /// <summary>
        /// This is the main class of the game
        /// </summary>
        public Game()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            _graphics.PreferredBackBufferWidth = 800; // _map.Width * 32;
            _graphics.PreferredBackBufferHeight = 640; // _map.Height * 32;
            _graphics.ApplyChanges();

            IsMouseVisible = true;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run
        /// This is where it can query for any required services and load any non-graphic related content
        /// Calling base.Initialize will enumerate through any components and initialize them as well
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load all of your content
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            _spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here            
            var bg = Content.Load<Texture2D>("img/backgrounds/bg_1");

            var start = Content.Load<Texture2D>("img/maps/start_1");
            var grass = Content.Load<Texture2D>("img/maps/grass_1");
            var path = Content.Load<Texture2D>("img/maps/path_1");
            var goal = Content.Load<Texture2D>("img/maps/goal_1");

            var enemyTexture = Content.Load<Texture2D>("img/enemy/enemy_1");
            var healthTexture = Content.Load<Texture2D>("img/enemy/healthbar");
            var bulletTexture = Content.Load<Texture2D>("img/bullet/bullet_1");

            var towerTextures = new Texture2D[]
            {
                Content.Load<Texture2D>("img/tower/arrowtower/tower_normal"),
                Content.Load<Texture2D>("img/tower/arrowtower/tower_active"),
                Content.Load<Texture2D>("img/tower/arrowtower/tower_inactive"),
                Content.Load<Texture2D>("img/tower/slowtower/tower_normal"),
                Content.Load<Texture2D>("img/tower/slowtower/tower_active"),
                Content.Load<Texture2D>("img/tower/slowtower/tower_inactive"),
                Content.Load<Texture2D>("img/tower/spiketower/tower_normal"),
                Content.Load<Texture2D>("img/tower/spiketower/tower_active"),
                Content.Load<Texture2D>("img/tower/spiketower/tower_inactive"),
            };

            var arrowTowerNormal = Content.Load<Texture2D>("img/tower/arrowtower/tower_normal");
            var arrowTowerActive = Content.Load<Texture2D>("img/tower/arrowtower/tower_active");
            var arrowTowerInactive = Content.Load<Texture2D>("img/tower/arrowtower/tower_inactive");
            var slowTowerNormal = Content.Load<Texture2D>("img/tower/slowtower/tower_normal");
            var slowTowerActive = Content.Load<Texture2D>("img/tower/slowtower/tower_active");
            var slowTowerInactive = Content.Load<Texture2D>("img/tower/slowtower/tower_inactive");
            var spikeTowerNormal = Content.Load<Texture2D>("img/tower/spiketower/tower_normal");
            var spikeTowerActive = Content.Load<Texture2D>("img/tower/spiketower/tower_active");
            var spikeTowerInactive = Content.Load<Texture2D>("img/tower/spiketower/tower_inactive");

            // Initialize the arrow button.
            _arrowButton = new Button(arrowTowerNormal, arrowTowerActive, arrowTowerInactive, new Vector2(615, 42));
            _arrowButton.Clicked += new EventHandler(ArrowButtonClicked);
            _slowButton = new Button(slowTowerNormal, slowTowerActive, slowTowerInactive, new Vector2(659, 42));
            _slowButton.Clicked += new EventHandler(SlowButtonClicked);
            _spikeButton = new Button(spikeTowerNormal, spikeTowerActive, spikeTowerInactive, new Vector2(703, 42));
            _spikeButton.Clicked += new EventHandler(SpikeButtonClicked);

            var spriteFont = Content.Load<SpriteFont>("font/Arial");

            _background.AddTexture(bg);

            _map.AddTexture(start);
            _map.AddTexture(grass);
            _map.AddTexture(path);
            _map.AddTexture(goal);

            _player = new Player(_map, towerTextures, bulletTexture);
            _waveManager = new WaveManager(_player, _map, 24, enemyTexture, healthTexture);
            _towermenu = new TowerMenu(arrowTowerNormal, spriteFont, new Vector2(615, 42));
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if(GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            this.Window.Title = _mouseInfos.GetMouseCoords();

            // TODO: Add your update logic here
            _waveManager.Update(gameTime);
            _player.Update(gameTime, _waveManager.Enemies);
            _arrowButton.Update(gameTime);
            _slowButton.Update(gameTime);
            _spikeButton.Update(gameTime);
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            // TODO: Add your drawing code here
            _spriteBatch.Begin();
            _background.Draw(_spriteBatch);
            _map.Draw(_spriteBatch);
            _waveManager.Draw(_spriteBatch);
            _player.Draw(_spriteBatch);
            _player.DrawPreview(_spriteBatch);
            _towermenu.Draw(_spriteBatch,_player);

            _arrowButton.Draw(_spriteBatch);
            _slowButton.Draw(_spriteBatch);
            _spikeButton.Draw(_spriteBatch);

            _spriteBatch.End();

            base.Draw(gameTime);
        }

        #endregion functions

        #region events

        /// <summary>
        /// On click it sets the index and the type of "Arrow Tower" status
        /// </summary>
        /// <param name="sender">The event sender</param>
        /// <param name="e">The event arguments</param>
        private void ArrowButtonClicked(object sender, EventArgs e)
        {
            _player.NewTowerType = "Arrow Tower";
            _player.NewTowerIndex = 0;
        }
        /// <summary>
        /// On press it sets the index and the type of "Arrow Tower" status
        /// </summary>
        /// <param name="sender">The event sender</param>
        /// <param name="e">The event arguments</param>
        private void ArrowButtonOnPress(object sender, EventArgs e)
        {
            _player.NewTowerType = "Arrow Tower";
            _player.NewTowerIndex = 0;
        }
        /// <summary>
        /// On click it sets the index and the type of "Slow Tower" status
        /// </summary>
        /// <param name="sender">The event sender</param>
        /// <param name="e">The event arguments</param>
        private void SlowButtonClicked(object sender, EventArgs e)
        {
            _player.NewTowerType = "Slow Tower";
            _player.NewTowerIndex = 3;
        }
        /// <summary>
        /// On press it sets the index and the type of "Slow Tower" status
        /// </summary>
        /// <param name="sender">The event sender</param>
        /// <param name="e">The event arguments</param>
        private void SlowButtonOnPress(object sender, EventArgs e)
        {
            _player.NewTowerType = "Slow Tower";
            _player.NewTowerIndex = 3;
        }
        /// <summary>
        /// On click it sets the index and the type of "Spike Tower" status
        /// </summary>
        /// <param name="sender">The event sender</param>
        /// <param name="e">The event arguments</param>
        private void SpikeButtonClicked(object sender, EventArgs e)
        {
            _player.NewTowerType = "Spike Tower";
            _player.NewTowerIndex = 6;
        }
        /// <summary>
        /// On press it sets the index and the type of "Spike Tower" status
        /// </summary>
        /// <param name="sender">The event sender</param>
        /// <param name="e">The event arguments</param>
        private void SpikeButtonOnPress(object sender, EventArgs e)
        {
            _player.NewTowerType = "Spike Tower";
            _player.NewTowerIndex = 6;
        }

        #endregion events

    }
}
